Errors and logs topic
Catch failed loads, cut streams, a silent output and failed calls, and read the logs.
Error stream
stream.error emits a PlayerError with two subtypes:
EndFileErrormeans a file stopped because of an error.LogErrormeans libmpv logged an error or a fatal message, or the package reported a silent output. Playback can go on.
player.stream.error.listen((error) {
switch (error) {
case EndFileError():
print('File failed: ${error.reason}, code ${error.code}');
if (error.isLoadingError) print('network or file not found');
case LogError():
print('libmpv error: ${error.message}');
}
});
An EndFileError tells the cause with isLoadingError, isAudioOutputError and isFormatError. A LogError carries the subsystem in prefix, such as ffmpeg, ao, demux or mpv_audio_kit.
End of a file
stream.endFile emits an MpvFileEndedEvent every time a file ends, with its reason. Read the entry from the event, because player.state can already describe the next entry.
The event carries the Media of the entry, its last position and its duration. media is null for an entry the player did not load itself, such as one from a playlist file or a raw command.
Cut streams
A dropped connection ends the file with a normal eof. Check readError and skippedSegments to tell a cut from the real end:
player.stream.endFile.listen((event) {
if (event.readError == true || (event.skippedSegments ?? 0) > 0) {
print('${event.media?.uri} was cut short at ${event.position}');
}
});
skippedSegments counts the HLS and DASH segments lost to errors.
The last entry of the playlist stays open at its end. state.playback.completed turns true, and state.network.readError tells how it ended:
player.stream.completed.listen((completed) {
if (completed && player.state.network.readError == true) {
print('The last entry was cut short at ${player.state.playback.position}');
}
});
Its endFile event comes later, with reason: stop, when the entry is stopped or replaced.
- The player retries a dropped connection first. It counts as a read error only after every retry failed. See the Network and cache topic.
- A seek after a cut reads again, and the entry plays on if the server answers.
completedturns false and true again, with the newreadError, also when the seek lands on the end. durationcan be an estimate, so comparing it withpositiondoes not detect a cut.
Silent output
stream.audioOutputState follows the audio output.
player.stream.audioOutputState.listen((state) {
switch (state) {
case AudioOutputState.closed: // no output open
case AudioOutputState.initializing: // opening
case AudioOutputState.active: // open
case AudioOutputState.failed: // no output could open
}
});
When no device opens, libmpv falls back to its null output. The state is active, the position runs and nothing is heard. stream.error then emits a LogError, unless you chose the null driver with setAudioDriver('null').
failed comes only when the null output cannot open either. stream.error then emits a LogError, and each file that cannot play ends with an EndFileError.
Logs
stream.log carries the messages of libmpv and FFmpeg. stream.internalLog carries the package's own messages, such as hook timeouts and resolver errors. Route them to different places:
player.stream.log.listen((entry) {
if (entry.level == LogLevel.error || entry.level == LogLevel.fatal) {
print('[${entry.level.mpvValue}] ${entry.prefix}: ${entry.text}');
}
});
player.stream.internalLog.listen((entry) {
print('[package:${entry.level.mpvValue}] ${entry.text}');
});
PlayerConfiguration.logLevel sets the starting level, LogLevel.warn by default.
player.setLogLevel(LogLevel.debug); // while developing
player.setLogLevel(LogLevel.off); // silence libmpv
Below LogLevel.error, the errors libmpv logs do not reach stream.error either.
Exceptions
A call that fails throws a PlayerException:
| Exception | When |
|---|---|
PlayerDisposedException |
The player was disposed |
PlayerInitException |
libmpv could not load or start, or is not of the libmpv release the package pins. Every call on that player throws it |
MpvCommandException |
libmpv rejected the request, such as a seek with no file loaded |
SourceException |
A source could not open, such as a missing asset or an unreadable content:// URI |
try {
await player.seek(position);
} on PlayerException catch (e) {
switch (e) {
case PlayerDisposedException():
break;
case PlayerInitException(:final message):
print('libmpv did not start: $message');
case MpvCommandException(:final name, :final message):
print('$name rejected: $message');
case SourceException(:final uri):
print('Cannot open $uri');
}
}
An invalid argument, such as a negative volume, throws ArgumentError or RangeError before the call reaches libmpv. next() and previous() return false when there is no entry to go to.
Classes
- PlayerError Errors and logs
-
Typed error events delivered on PlayerStream.error. A sealed union
over EndFileError (playback failures) and LogError
(
errororfatallog lines from an mpv subsystem). Pattern-match on the variant to distinguish them.